﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Windows;
using System.Windows.Controls;
using Red.Controls.Shell;
using Red.Controls.ViewModels;

namespace Red.Toolkit.HoudiniDispatch
{
    [Export( typeof( IEditorInfo ) )]
    public class EditorInfo : IEditorInfo
    {
        public string Name
        {
            get { return "Houdini Dispatch"; }
        }

        public Type WindowClass
        {
            get { return typeof( HoudiniDispatch ); }
        }

        public Type SettingsClass
        {
            get { return typeof( HoudiniDispatchSettings ); }
        }
    }
    
    /// <summary>
    /// Interaction logic for HoudiniDispatch.xaml
    /// </summary>
    public partial class HoudiniDispatch : RedEditorWindow
    {
        #region Data
        private readonly JobRoot _root;
        private string _selectedJobType;
        public List<string> JobTypes { get; set; }
        #endregion Data

        #region C-tor
        public HoudiniDispatch( IEditorHost host, EditorInstanceData instanceData, EditorSharedData sharedData )
            : base( host, instanceData, sharedData )
        {
            InitializeComponent();
            _root = new JobRoot();
            //_items.IsExpanded = true;
            _items.DataContext = _root;
            JobTypes = HoudiniJobManager.GetJobDefinitionsList();
            foreach ( string jt in JobTypes )
            {
                cmbJobType.Items.Add( jt );
            }
            cmbJobType.SelectedIndex = 1;
            Loaded += WindowLoaded;
        }
        #endregion C-tor

        #region Private Methods
        private void WindowLoaded( object sender, RoutedEventArgs e )
        {
            _items.IsExpanded = true;
        }

        private bool validateParams()
        {
            string errors = "Errors Found:\n";
            foreach ( DataItem ji in _root.Children )
            {
                switch(ji.Type)
                {
                    case( "Int" ):
                        errors += validateInt( ji );
                        break;
                    case ("Int:Ranged"):
                        errors += validateInt( ji );
                        break;
                    case ("Float"):
                        errors += validateFloat( ji );
                        break;
                    case ("Float:Ranged"):
                        errors += validateFloat( ji );
                        break;
                    case ("Vector"):
                        errors += validateVector( ji );
                        break;
                    default:
                        errors += validateString( ji );
                        break;
                }
            }
            if ( "" == errors.Trim() )
            {
                RedMessageBox.Show( this, RedDialogType.Ok, errors );
                return false;
            }
            return true;
        }

        private string validateString( DataItem ji )
        {
            string outStr = "";
            if ( 256 < ji.Value.Length )
            {
                outStr += ji.Title + ": Value exceeds 256 characters\n";
            }
            return outStr;
        }
        
        private string validateInt( DataItem ji )
        {
            int tempVal;
            string outStr = "";
            bool canParse = int.TryParse( ji.Value, out tempVal );
            if ( !canParse )
                outStr += ji.Title + ": Can not convert to Int" + ji.Value + "\n";
            if ( ("Int:Ranged" == ji.Type) && canParse )
            {
                JobItem_RangedInt jobItem = ji as JobItem_RangedInt;
                int minVal = jobItem.Min;
                int maxVal = jobItem.Max;
                if ( tempVal < minVal )
                    outStr += string.Format( "{0}: {1} is lower than Minimum ({2}) Value.\n", ji.Title, tempVal, minVal );
                else if ( tempVal > maxVal )
                    outStr += string.Format( "{0}: {1} is greater than Maximum ({2}) Value.\n", ji.Title, tempVal, maxVal );
            }
            return outStr;
        }

        private string validateFloat( DataItem ji  )
        {
            float tempVal;
            string outStr = "";
            bool canParse = float.TryParse( ji.Value, out tempVal );
            if ( !canParse )
                outStr += ji.Title + ": Can not convert to Float" + ji.Value + "\n";
            if ( ("Float:Ranged" == ji.Type) && canParse )
            {
                JobItem_RangedFloat jobItem = ji as JobItem_RangedFloat;
                float minVal = jobItem.Min;
                float maxVal = jobItem.Max;
                if ( tempVal < minVal )
                    outStr += string.Format( "{0}: {1} is lower than Minimum ({2}) Value.\n", ji.Title, tempVal, minVal );
                else if ( tempVal > maxVal )
                    outStr += string.Format( "{0}: {1} is greater than Maximum ({2}) Value.\n", ji.Title, tempVal, maxVal );
            }
            return outStr;
        }

        private string validateVector( DataItem ji )
        {
            string outStr = "";
            string[] splitVal = ji.Value.Split( ';' );
            float tempVal;
            bool canParse;
            foreach ( string val in splitVal )
            {
                canParse = float.TryParse( val, out tempVal );
                if ( !canParse )
                    outStr += string.Format( "{0}: Can not convert Vector Element to Float {1} in {2}.\n", ji.Title, tempVal, ji.Value );
            }

            return outStr;
        }
        
        private void btnSubmit_Click( object sender, RoutedEventArgs e )
        {
            string outText = "#JobDescriptor\n";
            outText += "user|s|" + Environment.UserName + "\n";
            if ( validateParams() )
            {
                foreach ( DataItem ji in _root.Children )
                {
                    if ( "Vector" == ji.Type )
                    {
                        outText += ji.Title + "|";
                        foreach ( DataItem di in ji.Children )
                        {
                            outText += di.Value + ";";
                        }
                        outText += "\n";
                    }
                    else
                        outText += ji.Title + "|" + ji.Value + "\n";
                }

                //Debug Output
                //RedMessageBox.Show( this, RedDialogType.Ok, outText );
                //Send to Server
                var Client = UdpUser.Connect();
                Client.Send( outText );
            }
        }


        private async void cmbJobType_SelectionChanged( object sender, SelectionChangedEventArgs e )
        {
            _selectedJobType = cmbJobType.SelectedValue.ToString();
            _root.SelectedJobType = _selectedJobType;
            _root.Children.Clear();
            await _root.RebuildAsync();
        }

        #endregion Private methods
    }
}
